home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / xmlrpclib.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  40KB  |  1,229 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. '''
  5. An XML-RPC client interface for Python.
  6.  
  7. The marshalling and response parser code can also be used to
  8. implement XML-RPC servers.
  9.  
  10. Exported exceptions:
  11.  
  12.   Error          Base class for client errors
  13.   ProtocolError  Indicates an HTTP protocol error
  14.   ResponseError  Indicates a broken response package
  15.   Fault          Indicates an XML-RPC fault package
  16.  
  17. Exported classes:
  18.  
  19.   ServerProxy    Represents a logical connection to an XML-RPC server
  20.  
  21.   MultiCall      Executor of boxcared xmlrpc requests
  22.   Boolean        boolean wrapper to generate a "boolean" XML-RPC value
  23.   DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
  24.                  localtime integer value to generate a "dateTime.iso8601"
  25.                  XML-RPC value
  26.   Binary         binary data wrapper
  27.  
  28.   SlowParser     Slow but safe standard parser (based on xmllib)
  29.   Marshaller     Generate an XML-RPC params chunk from a Python data structure
  30.   Unmarshaller   Unmarshal an XML-RPC response from incoming XML event message
  31.   Transport      Handles an HTTP transaction to an XML-RPC server
  32.   SafeTransport  Handles an HTTPS transaction to an XML-RPC server
  33.  
  34. Exported constants:
  35.  
  36.   True
  37.   False
  38.  
  39. Exported functions:
  40.  
  41.   boolean        Convert any Python value to an XML-RPC boolean
  42.   getparser      Create instance of the fastest available parser & attach
  43.                  to an unmarshalling object
  44.   dumps          Convert an argument tuple or a Fault instance to an XML-RPC
  45.                  request (or response, if the methodresponse option is used).
  46.   loads          Convert an XML-RPC packet to unmarshalled data plus a method
  47.                  name (None if not present).
  48. '''
  49. import re
  50. import string
  51. import time
  52. import operator
  53. from types import *
  54.  
  55. try:
  56.     unicode
  57. except NameError:
  58.     unicode = None
  59.  
  60.  
  61. try:
  62.     import datetime
  63. except ImportError:
  64.     datetime = None
  65.  
  66.  
  67. try:
  68.     _bool_is_builtin = False.__class__.__name__ == 'bool'
  69. except NameError:
  70.     _bool_is_builtin = 0
  71.  
  72.  
  73. def _decode(data, encoding, is8bit = re.compile('[\x80-\xff]').search):
  74.     if unicode and encoding and is8bit(data):
  75.         data = unicode(data, encoding)
  76.     
  77.     return data
  78.  
  79.  
  80. def escape(s, replace = string.replace):
  81.     s = replace(s, '&', '&')
  82.     s = replace(s, '<', '<')
  83.     return replace(s, '>', '>')
  84.  
  85. if unicode:
  86.     
  87.     def _stringify(string):
  88.         
  89.         try:
  90.             return string.encode('ascii')
  91.         except UnicodeError:
  92.             return string
  93.  
  94.  
  95. else:
  96.     
  97.     def _stringify(string):
  98.         return string
  99.  
  100. __version__ = '1.0.1'
  101. MAXINT = 0x7FFFFFFFL
  102. MININT = -0x80000000L
  103. PARSE_ERROR = -32700
  104. SERVER_ERROR = -32600
  105. APPLICATION_ERROR = -32500
  106. SYSTEM_ERROR = -32400
  107. TRANSPORT_ERROR = -32300
  108. NOT_WELLFORMED_ERROR = -32700
  109. UNSUPPORTED_ENCODING = -32701
  110. INVALID_ENCODING_CHAR = -32702
  111. INVALID_XMLRPC = -32600
  112. METHOD_NOT_FOUND = -32601
  113. INVALID_METHOD_PARAMS = -32602
  114. INTERNAL_ERROR = -32603
  115.  
  116. class Error(Exception):
  117.     '''Base class for client errors.'''
  118.     
  119.     def __str__(self):
  120.         return repr(self)
  121.  
  122.  
  123.  
  124. class ProtocolError(Error):
  125.     '''Indicates an HTTP protocol error.'''
  126.     
  127.     def __init__(self, url, errcode, errmsg, headers):
  128.         Error.__init__(self)
  129.         self.url = url
  130.         self.errcode = errcode
  131.         self.errmsg = errmsg
  132.         self.headers = headers
  133.  
  134.     
  135.     def __repr__(self):
  136.         return '<ProtocolError for %s: %s %s>' % (self.url, self.errcode, self.errmsg)
  137.  
  138.  
  139.  
  140. class ResponseError(Error):
  141.     '''Indicates a broken response package.'''
  142.     pass
  143.  
  144.  
  145. class Fault(Error):
  146.     '''Indicates an XML-RPC fault package.'''
  147.     
  148.     def __init__(self, faultCode, faultString, **extra):
  149.         Error.__init__(self)
  150.         self.faultCode = faultCode
  151.         self.faultString = faultString
  152.  
  153.     
  154.     def __repr__(self):
  155.         return '<Fault %s: %s>' % (self.faultCode, repr(self.faultString))
  156.  
  157.  
  158. if _bool_is_builtin:
  159.     boolean = Boolean = bool
  160.     True = True
  161.     False = False
  162. else:
  163.     
  164.     class Boolean:
  165.         '''Boolean-value wrapper.
  166.  
  167.         Use True or False to generate a "boolean" XML-RPC value.
  168.         '''
  169.         
  170.         def __init__(self, value = 0):
  171.             self.value = operator.truth(value)
  172.  
  173.         
  174.         def encode(self, out):
  175.             out.write('<value><boolean>%d</boolean></value>\n' % self.value)
  176.  
  177.         
  178.         def __cmp__(self, other):
  179.             if isinstance(other, Boolean):
  180.                 other = other.value
  181.             
  182.             return cmp(self.value, other)
  183.  
  184.         
  185.         def __repr__(self):
  186.             if self.value:
  187.                 return '<Boolean True at %x>' % id(self)
  188.             else:
  189.                 return '<Boolean False at %x>' % id(self)
  190.  
  191.         
  192.         def __int__(self):
  193.             return self.value
  194.  
  195.         
  196.         def __nonzero__(self):
  197.             return self.value
  198.  
  199.  
  200.     True = Boolean(1)
  201.     False = Boolean(0)
  202.     
  203.     def boolean(value, _truefalse = (False, True)):
  204.         """Convert any Python value to XML-RPC 'boolean'."""
  205.         return _truefalse[operator.truth(value)]
  206.  
  207.  
  208. class DateTime:
  209.     """DateTime wrapper for an ISO 8601 string or time tuple or
  210.     localtime integer value to generate 'dateTime.iso8601' XML-RPC
  211.     value.
  212.     """
  213.     
  214.     def __init__(self, value = 0):
  215.         if not isinstance(value, StringType):
  216.             if datetime and isinstance(value, datetime.datetime):
  217.                 self.value = value.strftime('%Y%m%dT%H:%M:%S')
  218.                 return None
  219.             
  220.             if datetime and isinstance(value, datetime.date):
  221.                 self.value = value.strftime('%Y%m%dT%H:%M:%S')
  222.                 return None
  223.             
  224.             if datetime and isinstance(value, datetime.time):
  225.                 today = datetime.datetime.now().strftime('%Y%m%d')
  226.                 self.value = value.strftime(today + 'T%H:%M:%S')
  227.                 return None
  228.             
  229.             if not isinstance(value, (TupleType, time.struct_time)):
  230.                 if value == 0:
  231.                     value = time.time()
  232.                 
  233.                 value = time.localtime(value)
  234.             
  235.             value = time.strftime('%Y%m%dT%H:%M:%S', value)
  236.         
  237.         self.value = value
  238.  
  239.     
  240.     def __cmp__(self, other):
  241.         if isinstance(other, DateTime):
  242.             other = other.value
  243.         
  244.         return cmp(self.value, other)
  245.  
  246.     
  247.     def __str__(self):
  248.         return self.value
  249.  
  250.     
  251.     def __repr__(self):
  252.         return '<DateTime %s at %x>' % (repr(self.value), id(self))
  253.  
  254.     
  255.     def decode(self, data):
  256.         data = str(data)
  257.         self.value = string.strip(data)
  258.  
  259.     
  260.     def encode(self, out):
  261.         out.write('<value><dateTime.iso8601>')
  262.         out.write(self.value)
  263.         out.write('</dateTime.iso8601></value>\n')
  264.  
  265.  
  266.  
  267. def _datetime(data):
  268.     value = DateTime()
  269.     value.decode(data)
  270.     return value
  271.  
  272.  
  273. def _datetime_type(data):
  274.     t = time.strptime(data, '%Y%m%dT%H:%M:%S')
  275.     return datetime.datetime(*tuple(t)[:6])
  276.  
  277. import base64
  278.  
  279. try:
  280.     import cStringIO as StringIO
  281. except ImportError:
  282.     import StringIO
  283.  
  284.  
  285. class Binary:
  286.     '''Wrapper for binary data.'''
  287.     
  288.     def __init__(self, data = None):
  289.         self.data = data
  290.  
  291.     
  292.     def __str__(self):
  293.         if not self.data:
  294.             pass
  295.         return ''
  296.  
  297.     
  298.     def __cmp__(self, other):
  299.         if isinstance(other, Binary):
  300.             other = other.data
  301.         
  302.         return cmp(self.data, other)
  303.  
  304.     
  305.     def decode(self, data):
  306.         self.data = base64.decodestring(data)
  307.  
  308.     
  309.     def encode(self, out):
  310.         out.write('<value><base64>\n')
  311.         base64.encode(StringIO.StringIO(self.data), out)
  312.         out.write('</base64></value>\n')
  313.  
  314.  
  315.  
  316. def _binary(data):
  317.     value = Binary()
  318.     value.decode(data)
  319.     return value
  320.  
  321. WRAPPERS = (DateTime, Binary)
  322. if not _bool_is_builtin:
  323.     WRAPPERS = WRAPPERS + (Boolean,)
  324.  
  325.  
  326. try:
  327.     import _xmlrpclib
  328.     FastParser = _xmlrpclib.Parser
  329.     FastUnmarshaller = _xmlrpclib.Unmarshaller
  330. except (AttributeError, ImportError):
  331.     FastParser = None
  332.     FastUnmarshaller = None
  333.  
  334.  
  335. try:
  336.     import _xmlrpclib
  337.     FastMarshaller = _xmlrpclib.Marshaller
  338. except (AttributeError, ImportError):
  339.     FastMarshaller = None
  340.  
  341.  
  342. try:
  343.     import sgmlop
  344.     if not hasattr(sgmlop, 'XMLParser'):
  345.         raise ImportError
  346. except ImportError:
  347.     SgmlopParser = None
  348.  
  349.  
  350. class SgmlopParser:
  351.     
  352.     def __init__(self, target):
  353.         self.finish_starttag = target.start
  354.         self.finish_endtag = target.end
  355.         self.handle_data = target.data
  356.         self.handle_xml = target.xml
  357.         self.parser = sgmlop.XMLParser()
  358.         self.parser.register(self)
  359.         self.feed = self.parser.feed
  360.         self.entity = {
  361.             'amp': '&',
  362.             'gt': '>',
  363.             'lt': '<',
  364.             'apos': "'",
  365.             'quot': '"' }
  366.  
  367.     
  368.     def close(self):
  369.         
  370.         try:
  371.             self.parser.close()
  372.         finally:
  373.             self.parser = None
  374.             self.feed = None
  375.  
  376.  
  377.     
  378.     def handle_proc(self, tag, attr):
  379.         m = re.search('encoding\\s*=\\s*[\'"]([^"\']+)["\']', attr)
  380.         if m:
  381.             self.handle_xml(m.group(1), 1)
  382.         
  383.  
  384.     
  385.     def handle_entityref(self, entity):
  386.         
  387.         try:
  388.             self.handle_data(self.entity[entity])
  389.         except KeyError:
  390.             self.handle_data('&%s;' % entity)
  391.  
  392.  
  393.  
  394.  
  395. try:
  396.     from xml.parsers import expat
  397.     if not hasattr(expat, 'ParserCreate'):
  398.         raise ImportError
  399. except ImportError:
  400.     ExpatParser = None
  401.  
  402.  
  403. class ExpatParser:
  404.     
  405.     def __init__(self, target):
  406.         self._parser = parser = expat.ParserCreate(None, None)
  407.         self._target = target
  408.         parser.StartElementHandler = target.start
  409.         parser.EndElementHandler = target.end
  410.         parser.CharacterDataHandler = target.data
  411.         encoding = None
  412.         if not parser.returns_unicode:
  413.             encoding = 'utf-8'
  414.         
  415.         target.xml(encoding, None)
  416.  
  417.     
  418.     def feed(self, data):
  419.         self._parser.Parse(data, 0)
  420.  
  421.     
  422.     def close(self):
  423.         self._parser.Parse('', 1)
  424.         del self._target
  425.         del self._parser
  426.  
  427.  
  428.  
  429. class SlowParser:
  430.     '''Default XML parser (based on xmllib.XMLParser).'''
  431.     
  432.     def __init__(self, target):
  433.         import xmllib as xmllib
  434.         if xmllib.XMLParser not in SlowParser.__bases__:
  435.             SlowParser.__bases__ = (xmllib.XMLParser,)
  436.         
  437.         self.handle_xml = target.xml
  438.         self.unknown_starttag = target.start
  439.         self.handle_data = target.data
  440.         self.handle_cdata = target.data
  441.         self.unknown_endtag = target.end
  442.         
  443.         try:
  444.             xmllib.XMLParser.__init__(self, accept_utf8 = 1)
  445.         except TypeError:
  446.             xmllib.XMLParser.__init__(self)
  447.  
  448.  
  449.  
  450.  
  451. class Marshaller:
  452.     '''Generate an XML-RPC params chunk from a Python data structure.
  453.  
  454.     Create a Marshaller instance for each set of parameters, and use
  455.     the "dumps" method to convert your data (represented as a tuple)
  456.     to an XML-RPC params chunk.  To write a fault response, pass a
  457.     Fault instance instead.  You may prefer to use the "dumps" module
  458.     function for this purpose.
  459.     '''
  460.     
  461.     def __init__(self, encoding = None, allow_none = 0):
  462.         self.memo = { }
  463.         self.data = None
  464.         self.encoding = encoding
  465.         self.allow_none = allow_none
  466.  
  467.     dispatch = { }
  468.     
  469.     def dumps(self, values):
  470.         out = []
  471.         write = out.append
  472.         dump = self._Marshaller__dump
  473.         if isinstance(values, Fault):
  474.             write('<fault>\n')
  475.             dump({
  476.                 'faultCode': values.faultCode,
  477.                 'faultString': values.faultString }, write)
  478.             write('</fault>\n')
  479.         else:
  480.             write('<params>\n')
  481.             for v in values:
  482.                 write('<param>\n')
  483.                 dump(v, write)
  484.                 write('</param>\n')
  485.             
  486.             write('</params>\n')
  487.         result = string.join(out, '')
  488.         return result
  489.  
  490.     
  491.     def __dump(self, value, write):
  492.         
  493.         try:
  494.             f = self.dispatch[type(value)]
  495.         except KeyError:
  496.             raise TypeError, 'cannot marshal %s objects' % type(value)
  497.  
  498.         f(self, value, write)
  499.  
  500.     
  501.     def dump_nil(self, value, write):
  502.         if not self.allow_none:
  503.             raise TypeError, 'cannot marshal None unless allow_none is enabled'
  504.         
  505.         write('<value><nil/></value>')
  506.  
  507.     dispatch[NoneType] = dump_nil
  508.     
  509.     def dump_int(self, value, write):
  510.         if value > MAXINT or value < MININT:
  511.             raise OverflowError, 'int exceeds XML-RPC limits'
  512.         
  513.         write('<value><int>')
  514.         write(str(value))
  515.         write('</int></value>\n')
  516.  
  517.     dispatch[IntType] = dump_int
  518.     if _bool_is_builtin:
  519.         
  520.         def dump_bool(self, value, write):
  521.             write('<value><boolean>')
  522.             if not value or '1':
  523.                 pass
  524.             write('0')
  525.             write('</boolean></value>\n')
  526.  
  527.         dispatch[bool] = dump_bool
  528.     
  529.     
  530.     def dump_long(self, value, write):
  531.         if value > MAXINT or value < MININT:
  532.             raise OverflowError, 'long int exceeds XML-RPC limits'
  533.         
  534.         write('<value><int>')
  535.         write(str(int(value)))
  536.         write('</int></value>\n')
  537.  
  538.     dispatch[LongType] = dump_long
  539.     
  540.     def dump_double(self, value, write):
  541.         write('<value><double>')
  542.         write(repr(value))
  543.         write('</double></value>\n')
  544.  
  545.     dispatch[FloatType] = dump_double
  546.     
  547.     def dump_string(self, value, write, escape = escape):
  548.         write('<value><string>')
  549.         write(escape(value))
  550.         write('</string></value>\n')
  551.  
  552.     dispatch[StringType] = dump_string
  553.     if unicode:
  554.         
  555.         def dump_unicode(self, value, write, escape = escape):
  556.             value = value.encode(self.encoding)
  557.             write('<value><string>')
  558.             write(escape(value))
  559.             write('</string></value>\n')
  560.  
  561.         dispatch[UnicodeType] = dump_unicode
  562.     
  563.     
  564.     def dump_array(self, value, write):
  565.         i = id(value)
  566.         if self.memo.has_key(i):
  567.             raise TypeError, 'cannot marshal recursive sequences'
  568.         
  569.         self.memo[i] = None
  570.         dump = self._Marshaller__dump
  571.         write('<value><array><data>\n')
  572.         for v in value:
  573.             dump(v, write)
  574.         
  575.         write('</data></array></value>\n')
  576.         del self.memo[i]
  577.  
  578.     dispatch[TupleType] = dump_array
  579.     dispatch[ListType] = dump_array
  580.     
  581.     def dump_struct(self, value, write, escape = escape):
  582.         i = id(value)
  583.         if self.memo.has_key(i):
  584.             raise TypeError, 'cannot marshal recursive dictionaries'
  585.         
  586.         self.memo[i] = None
  587.         dump = self._Marshaller__dump
  588.         write('<value><struct>\n')
  589.         for k, v in value.items():
  590.             write('<member>\n')
  591.             if type(k) is not StringType:
  592.                 if unicode and type(k) is UnicodeType:
  593.                     k = k.encode(self.encoding)
  594.                 else:
  595.                     raise TypeError, 'dictionary key must be string'
  596.             
  597.             write('<name>%s</name>\n' % escape(k))
  598.             dump(v, write)
  599.             write('</member>\n')
  600.         
  601.         write('</struct></value>\n')
  602.         del self.memo[i]
  603.  
  604.     dispatch[DictType] = dump_struct
  605.     if datetime:
  606.         
  607.         def dump_datetime(self, value, write):
  608.             write('<value><dateTime.iso8601>')
  609.             write(value.strftime('%Y%m%dT%H:%M:%S'))
  610.             write('</dateTime.iso8601></value>\n')
  611.  
  612.         dispatch[datetime.datetime] = dump_datetime
  613.         
  614.         def dump_date(self, value, write):
  615.             write('<value><dateTime.iso8601>')
  616.             write(value.strftime('%Y%m%dT00:00:00'))
  617.             write('</dateTime.iso8601></value>\n')
  618.  
  619.         dispatch[datetime.date] = dump_date
  620.         
  621.         def dump_time(self, value, write):
  622.             write('<value><dateTime.iso8601>')
  623.             write(datetime.datetime.now().date().strftime('%Y%m%dT'))
  624.             write(value.strftime('%H:%M:%S'))
  625.             write('</dateTime.iso8601></value>\n')
  626.  
  627.         dispatch[datetime.time] = dump_time
  628.     
  629.     
  630.     def dump_instance(self, value, write):
  631.         if value.__class__ in WRAPPERS:
  632.             self.write = write
  633.             value.encode(self)
  634.             del self.write
  635.         else:
  636.             self.dump_struct(value.__dict__, write)
  637.  
  638.     dispatch[InstanceType] = dump_instance
  639.  
  640.  
  641. class Unmarshaller:
  642.     '''Unmarshal an XML-RPC response, based on incoming XML event
  643.     messages (start, data, end).  Call close() to get the resulting
  644.     data structure.
  645.  
  646.     Note that this reader is fairly tolerant, and gladly accepts bogus
  647.     XML-RPC data without complaining (but not bogus XML).
  648.     '''
  649.     
  650.     def __init__(self, use_datetime = 0):
  651.         self._type = None
  652.         self._stack = []
  653.         self._marks = []
  654.         self._data = []
  655.         self._methodname = None
  656.         self._encoding = 'utf-8'
  657.         self.append = self._stack.append
  658.         self._use_datetime = use_datetime
  659.         if use_datetime and not datetime:
  660.             raise ValueError, 'the datetime module is not available'
  661.         
  662.  
  663.     
  664.     def close(self):
  665.         if self._type is None or self._marks:
  666.             raise ResponseError()
  667.         
  668.         if self._type == 'fault':
  669.             raise Fault(**self._stack[0])
  670.         
  671.         return tuple(self._stack)
  672.  
  673.     
  674.     def getmethodname(self):
  675.         return self._methodname
  676.  
  677.     
  678.     def xml(self, encoding, standalone):
  679.         self._encoding = encoding
  680.  
  681.     
  682.     def start(self, tag, attrs):
  683.         if tag == 'array' or tag == 'struct':
  684.             self._marks.append(len(self._stack))
  685.         
  686.         self._data = []
  687.         self._value = tag == 'value'
  688.  
  689.     
  690.     def data(self, text):
  691.         self._data.append(text)
  692.  
  693.     
  694.     def end(self, tag, join = string.join):
  695.         
  696.         try:
  697.             f = self.dispatch[tag]
  698.         except KeyError:
  699.             pass
  700.  
  701.         return f(self, join(self._data, ''))
  702.  
  703.     
  704.     def end_dispatch(self, tag, data):
  705.         
  706.         try:
  707.             f = self.dispatch[tag]
  708.         except KeyError:
  709.             pass
  710.  
  711.         return f(self, data)
  712.  
  713.     dispatch = { }
  714.     
  715.     def end_nil(self, data):
  716.         self.append(None)
  717.         self._value = 0
  718.  
  719.     dispatch['nil'] = end_nil
  720.     
  721.     def end_boolean(self, data):
  722.         if data == '0':
  723.             self.append(False)
  724.         elif data == '1':
  725.             self.append(True)
  726.         else:
  727.             raise TypeError, 'bad boolean value'
  728.         self._value = 0
  729.  
  730.     dispatch['boolean'] = end_boolean
  731.     
  732.     def end_int(self, data):
  733.         self.append(int(data))
  734.         self._value = 0
  735.  
  736.     dispatch['i4'] = end_int
  737.     dispatch['int'] = end_int
  738.     
  739.     def end_double(self, data):
  740.         self.append(float(data))
  741.         self._value = 0
  742.  
  743.     dispatch['double'] = end_double
  744.     
  745.     def end_string(self, data):
  746.         if self._encoding:
  747.             data = _decode(data, self._encoding)
  748.         
  749.         self.append(_stringify(data))
  750.         self._value = 0
  751.  
  752.     dispatch['string'] = end_string
  753.     dispatch['name'] = end_string
  754.     
  755.     def end_array(self, data):
  756.         mark = self._marks.pop()
  757.         self._stack[mark:] = [
  758.             self._stack[mark:]]
  759.         self._value = 0
  760.  
  761.     dispatch['array'] = end_array
  762.     
  763.     def end_struct(self, data):
  764.         mark = self._marks.pop()
  765.         dict = { }
  766.         items = self._stack[mark:]
  767.         for i in range(0, len(items), 2):
  768.             dict[_stringify(items[i])] = items[i + 1]
  769.         
  770.         self._stack[mark:] = [
  771.             dict]
  772.         self._value = 0
  773.  
  774.     dispatch['struct'] = end_struct
  775.     
  776.     def end_base64(self, data):
  777.         value = Binary()
  778.         value.decode(data)
  779.         self.append(value)
  780.         self._value = 0
  781.  
  782.     dispatch['base64'] = end_base64
  783.     
  784.     def end_dateTime(self, data):
  785.         value = DateTime()
  786.         value.decode(data)
  787.         if self._use_datetime:
  788.             value = _datetime_type(data)
  789.         
  790.         self.append(value)
  791.  
  792.     dispatch['dateTime.iso8601'] = end_dateTime
  793.     
  794.     def end_value(self, data):
  795.         if self._value:
  796.             self.end_string(data)
  797.         
  798.  
  799.     dispatch['value'] = end_value
  800.     
  801.     def end_params(self, data):
  802.         self._type = 'params'
  803.  
  804.     dispatch['params'] = end_params
  805.     
  806.     def end_fault(self, data):
  807.         self._type = 'fault'
  808.  
  809.     dispatch['fault'] = end_fault
  810.     
  811.     def end_methodName(self, data):
  812.         if self._encoding:
  813.             data = _decode(data, self._encoding)
  814.         
  815.         self._methodname = data
  816.         self._type = 'methodName'
  817.  
  818.     dispatch['methodName'] = end_methodName
  819.  
  820.  
  821. class _MultiCallMethod:
  822.     
  823.     def __init__(self, call_list, name):
  824.         self._MultiCallMethod__call_list = call_list
  825.         self._MultiCallMethod__name = name
  826.  
  827.     
  828.     def __getattr__(self, name):
  829.         return _MultiCallMethod(self._MultiCallMethod__call_list, '%s.%s' % (self._MultiCallMethod__name, name))
  830.  
  831.     
  832.     def __call__(self, *args):
  833.         self._MultiCallMethod__call_list.append((self._MultiCallMethod__name, args))
  834.  
  835.  
  836.  
  837. class MultiCallIterator:
  838.     '''Iterates over the results of a multicall. Exceptions are
  839.     thrown in response to xmlrpc faults.'''
  840.     
  841.     def __init__(self, results):
  842.         self.results = results
  843.  
  844.     
  845.     def __getitem__(self, i):
  846.         item = self.results[i]
  847.         if type(item) == type({ }):
  848.             raise Fault(item['faultCode'], item['faultString'])
  849.         elif type(item) == type([]):
  850.             return item[0]
  851.         else:
  852.             raise ValueError, 'unexpected type in multicall result'
  853.  
  854.  
  855.  
  856. class MultiCall:
  857.     '''server -> a object used to boxcar method calls
  858.  
  859.     server should be a ServerProxy object.
  860.  
  861.     Methods can be added to the MultiCall using normal
  862.     method call syntax e.g.:
  863.  
  864.     multicall = MultiCall(server_proxy)
  865.     multicall.add(2,3)
  866.     multicall.get_address("Guido")
  867.  
  868.     To execute the multicall, call the MultiCall object e.g.:
  869.  
  870.     add_result, address = multicall()
  871.     '''
  872.     
  873.     def __init__(self, server):
  874.         self._MultiCall__server = server
  875.         self._MultiCall__call_list = []
  876.  
  877.     
  878.     def __repr__(self):
  879.         return '<MultiCall at %x>' % id(self)
  880.  
  881.     __str__ = __repr__
  882.     
  883.     def __getattr__(self, name):
  884.         return _MultiCallMethod(self._MultiCall__call_list, name)
  885.  
  886.     
  887.     def __call__(self):
  888.         marshalled_list = []
  889.         for name, args in self._MultiCall__call_list:
  890.             marshalled_list.append({
  891.                 'methodName': name,
  892.                 'params': args })
  893.         
  894.         return MultiCallIterator(self._MultiCall__server.system.multicall(marshalled_list))
  895.  
  896.  
  897.  
  898. def getparser(use_datetime = 0):
  899.     '''getparser() -> parser, unmarshaller
  900.  
  901.     Create an instance of the fastest available parser, and attach it
  902.     to an unmarshalling object.  Return both objects.
  903.     '''
  904.     if use_datetime and not datetime:
  905.         raise ValueError, 'the datetime module is not available'
  906.     
  907.     if FastParser and FastUnmarshaller:
  908.         if use_datetime:
  909.             mkdatetime = _datetime_type
  910.         else:
  911.             mkdatetime = _datetime
  912.         target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
  913.         parser = FastParser(target)
  914.     else:
  915.         target = Unmarshaller(use_datetime = use_datetime)
  916.         if FastParser:
  917.             parser = FastParser(target)
  918.         elif SgmlopParser:
  919.             parser = SgmlopParser(target)
  920.         elif ExpatParser:
  921.             parser = ExpatParser(target)
  922.         else:
  923.             parser = SlowParser(target)
  924.     return (parser, target)
  925.  
  926.  
  927. def dumps(params, methodname = None, methodresponse = None, encoding = None, allow_none = 0):
  928.     '''data [,options] -> marshalled data
  929.  
  930.     Convert an argument tuple or a Fault instance to an XML-RPC
  931.     request (or response, if the methodresponse option is used).
  932.  
  933.     In addition to the data object, the following options can be given
  934.     as keyword arguments:
  935.  
  936.         methodname: the method name for a methodCall packet
  937.  
  938.         methodresponse: true to create a methodResponse packet.
  939.         If this option is used with a tuple, the tuple must be
  940.         a singleton (i.e. it can contain only one element).
  941.  
  942.         encoding: the packet encoding (default is UTF-8)
  943.  
  944.     All 8-bit strings in the data structure are assumed to use the
  945.     packet encoding.  Unicode strings are automatically converted,
  946.     where necessary.
  947.     '''
  948.     if not isinstance(params, TupleType) and isinstance(params, Fault):
  949.         raise AssertionError, 'argument must be tuple or Fault instance'
  950.     if isinstance(params, Fault):
  951.         methodresponse = 1
  952.     elif methodresponse and isinstance(params, TupleType):
  953.         if not len(params) == 1:
  954.             raise AssertionError, 'response tuple must be a singleton'
  955.     
  956.     if not encoding:
  957.         encoding = 'utf-8'
  958.     
  959.     if FastMarshaller:
  960.         m = FastMarshaller(encoding)
  961.     else:
  962.         m = Marshaller(encoding, allow_none)
  963.     data = m.dumps(params)
  964.     if encoding != 'utf-8':
  965.         xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
  966.     else:
  967.         xmlheader = "<?xml version='1.0'?>\n"
  968.     if methodname:
  969.         if not isinstance(methodname, StringType):
  970.             methodname = methodname.encode(encoding)
  971.         
  972.         data = (xmlheader, '<methodCall>\n<methodName>', methodname, '</methodName>\n', data, '</methodCall>\n')
  973.     elif methodresponse:
  974.         data = (xmlheader, '<methodResponse>\n', data, '</methodResponse>\n')
  975.     else:
  976.         return data
  977.     return string.join(data, '')
  978.  
  979.  
  980. def loads(data, use_datetime = 0):
  981.     '''data -> unmarshalled data, method name
  982.  
  983.     Convert an XML-RPC packet to unmarshalled data plus a method
  984.     name (None if not present).
  985.  
  986.     If the XML-RPC packet represents a fault condition, this function
  987.     raises a Fault exception.
  988.     '''
  989.     (p, u) = getparser(use_datetime = use_datetime)
  990.     p.feed(data)
  991.     p.close()
  992.     return (u.close(), u.getmethodname())
  993.  
  994.  
  995. class _Method:
  996.     
  997.     def __init__(self, send, name):
  998.         self._Method__send = send
  999.         self._Method__name = name
  1000.  
  1001.     
  1002.     def __getattr__(self, name):
  1003.         return _Method(self._Method__send, '%s.%s' % (self._Method__name, name))
  1004.  
  1005.     
  1006.     def __call__(self, *args):
  1007.         return self._Method__send(self._Method__name, args)
  1008.  
  1009.  
  1010.  
  1011. class Transport:
  1012.     '''Handles an HTTP transaction to an XML-RPC server.'''
  1013.     user_agent = 'xmlrpclib.py/%s (by www.pythonware.com)' % __version__
  1014.     
  1015.     def __init__(self, use_datetime = 0):
  1016.         self._use_datetime = use_datetime
  1017.  
  1018.     
  1019.     def request(self, host, handler, request_body, verbose = 0):
  1020.         h = self.make_connection(host)
  1021.         if verbose:
  1022.             h.set_debuglevel(1)
  1023.         
  1024.         self.send_request(h, handler, request_body)
  1025.         self.send_host(h, host)
  1026.         self.send_user_agent(h)
  1027.         self.send_content(h, request_body)
  1028.         (errcode, errmsg, headers) = h.getreply()
  1029.         if errcode != 200:
  1030.             raise ProtocolError(host + handler, errcode, errmsg, headers)
  1031.         
  1032.         self.verbose = verbose
  1033.         
  1034.         try:
  1035.             sock = h._conn.sock
  1036.         except AttributeError:
  1037.             sock = None
  1038.  
  1039.         return self._parse_response(h.getfile(), sock)
  1040.  
  1041.     
  1042.     def getparser(self):
  1043.         return getparser(use_datetime = self._use_datetime)
  1044.  
  1045.     
  1046.     def get_host_info(self, host):
  1047.         x509 = { }
  1048.         if isinstance(host, TupleType):
  1049.             (host, x509) = host
  1050.         
  1051.         import urllib as urllib
  1052.         (auth, host) = urllib.splituser(host)
  1053.         if auth:
  1054.             import base64
  1055.             auth = base64.encodestring(urllib.unquote(auth))
  1056.             auth = string.join(string.split(auth), '')
  1057.             extra_headers = [
  1058.                 ('Authorization', 'Basic ' + auth)]
  1059.         else:
  1060.             extra_headers = None
  1061.         return (host, extra_headers, x509)
  1062.  
  1063.     
  1064.     def make_connection(self, host):
  1065.         import httplib as httplib
  1066.         (host, extra_headers, x509) = self.get_host_info(host)
  1067.         return httplib.HTTP(host)
  1068.  
  1069.     
  1070.     def send_request(self, connection, handler, request_body):
  1071.         connection.putrequest('POST', handler)
  1072.  
  1073.     
  1074.     def send_host(self, connection, host):
  1075.         (host, extra_headers, x509) = self.get_host_info(host)
  1076.         connection.putheader('Host', host)
  1077.         if extra_headers:
  1078.             if isinstance(extra_headers, DictType):
  1079.                 extra_headers = extra_headers.items()
  1080.             
  1081.             for key, value in extra_headers:
  1082.                 connection.putheader(key, value)
  1083.             
  1084.         
  1085.  
  1086.     
  1087.     def send_user_agent(self, connection):
  1088.         connection.putheader('User-Agent', self.user_agent)
  1089.  
  1090.     
  1091.     def send_content(self, connection, request_body):
  1092.         connection.putheader('Content-Type', 'text/xml')
  1093.         connection.putheader('Content-Length', str(len(request_body)))
  1094.         connection.endheaders()
  1095.         if request_body:
  1096.             connection.send(request_body)
  1097.         
  1098.  
  1099.     
  1100.     def parse_response(self, file):
  1101.         return self._parse_response(file, None)
  1102.  
  1103.     
  1104.     def _parse_response(self, file, sock):
  1105.         (p, u) = self.getparser()
  1106.         while sock:
  1107.             response = sock.recv(1024)
  1108.         response = file.read(1024)
  1109.         if not response:
  1110.             break
  1111.         
  1112.         if self.verbose:
  1113.             print 'body:', repr(response)
  1114.         
  1115.         p.feed(response)
  1116.         continue
  1117.         file.close()
  1118.         p.close()
  1119.         return u.close()
  1120.  
  1121.  
  1122.  
  1123. class SafeTransport(Transport):
  1124.     '''Handles an HTTPS transaction to an XML-RPC server.'''
  1125.     
  1126.     def make_connection(self, host):
  1127.         import httplib
  1128.         (host, extra_headers, x509) = self.get_host_info(host)
  1129.         
  1130.         try:
  1131.             HTTPS = httplib.HTTPS
  1132.         except AttributeError:
  1133.             raise NotImplementedError("your version of httplib doesn't support HTTPS")
  1134.  
  1135.         if not x509:
  1136.             pass
  1137.         return HTTPS(host, None, **{ })
  1138.  
  1139.  
  1140.  
  1141. class ServerProxy:
  1142.     '''uri [,options] -> a logical connection to an XML-RPC server
  1143.  
  1144.     uri is the connection point on the server, given as
  1145.     scheme://host/target.
  1146.  
  1147.     The standard implementation always supports the "http" scheme.  If
  1148.     SSL socket support is available (Python 2.0), it also supports
  1149.     "https".
  1150.  
  1151.     If the target part and the slash preceding it are both omitted,
  1152.     "/RPC2" is assumed.
  1153.  
  1154.     The following options can be given as keyword arguments:
  1155.  
  1156.         transport: a transport factory
  1157.         encoding: the request encoding (default is UTF-8)
  1158.  
  1159.     All 8-bit strings passed to the server proxy are assumed to use
  1160.     the given encoding.
  1161.     '''
  1162.     
  1163.     def __init__(self, uri, transport = None, encoding = None, verbose = 0, allow_none = 0, use_datetime = 0):
  1164.         import urllib
  1165.         (type, uri) = urllib.splittype(uri)
  1166.         if type not in ('http', 'https'):
  1167.             raise IOError, 'unsupported XML-RPC protocol'
  1168.         
  1169.         (self._ServerProxy__host, self._ServerProxy__handler) = urllib.splithost(uri)
  1170.         if not self._ServerProxy__handler:
  1171.             self._ServerProxy__handler = '/RPC2'
  1172.         
  1173.         if transport is None:
  1174.             if type == 'https':
  1175.                 transport = SafeTransport(use_datetime = use_datetime)
  1176.             else:
  1177.                 transport = Transport(use_datetime = use_datetime)
  1178.         
  1179.         self._ServerProxy__transport = transport
  1180.         self._ServerProxy__encoding = encoding
  1181.         self._ServerProxy__verbose = verbose
  1182.         self._ServerProxy__allow_none = allow_none
  1183.  
  1184.     
  1185.     def __request(self, methodname, params):
  1186.         request = dumps(params, methodname, encoding = self._ServerProxy__encoding, allow_none = self._ServerProxy__allow_none)
  1187.         response = self._ServerProxy__transport.request(self._ServerProxy__host, self._ServerProxy__handler, request, verbose = self._ServerProxy__verbose)
  1188.         if len(response) == 1:
  1189.             response = response[0]
  1190.         
  1191.         return response
  1192.  
  1193.     
  1194.     def __repr__(self):
  1195.         return '<ServerProxy for %s%s>' % (self._ServerProxy__host, self._ServerProxy__handler)
  1196.  
  1197.     __str__ = __repr__
  1198.     
  1199.     def __getattr__(self, name):
  1200.         return _Method(self._ServerProxy__request, name)
  1201.  
  1202.  
  1203. Server = ServerProxy
  1204. if __name__ == '__main__':
  1205.     server = ServerProxy('http://time.xmlrpc.com/RPC2')
  1206.     print server
  1207.     
  1208.     try:
  1209.         print server.currentTime.getCurrentTime()
  1210.     except Error:
  1211.         v = None
  1212.         print 'ERROR', v
  1213.  
  1214.     multi = MultiCall(server)
  1215.     multi.currentTime.getCurrentTime()
  1216.     multi.currentTime.getCurrentTime()
  1217.     
  1218.     try:
  1219.         for response in multi():
  1220.             print response
  1221.     except Error:
  1222.         v = None
  1223.         print 'ERROR', v
  1224.     except:
  1225.         None<EXCEPTION MATCH>Error
  1226.     
  1227.  
  1228. None<EXCEPTION MATCH>Error
  1229.